/*
 * Copyright (c) 2010 Mathew Hall, University of Sheffield.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided
 * with the distribution.
 *
 * Neither the name of the University of Sheffield nor the names of its
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
package gpinterpreter.vector;

import gpinterpreter.Instruction;
import gpinterpreter.Interpreter;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import primitives.cluster.ClusterHead;
import primitives.cluster.IClusterLevel;
import primitives.cluster.ClusterNode;
import primitives.cluster.ClusterUtils;
import primitives.util.UndefinedIndexException;

/**
 * VecInterpreter - basic interpreter for solution representation Walks down a
 * List of {@link VecInstruction}s modifying a given Tree accordingly.
 * 
 * @author mat
 * 
 */
public class VecInterpreter extends Interpreter<VecInstruction>{

	public VecInterpreter(List<VecInstruction> program, ClusterHead tree){
		super(program,tree);		
	}


	// TODO: make this throw an error when tree is empty.

	public void execute(VecInstruction i) {
		VecInstruction nextInstruction = i;
		IClusterLevel c1, c2;
		switch (nextInstruction.getType()) {
		case MERGE:
			if (nextInstruction.getOperand1() == nextInstruction.getOperand2())
				break;
                        if (nextInstruction.getOperand1() == 0
					|| nextInstruction.getOperand2() == 0) {
                            Logger.getLogger(VecInterpreter.class.getName()).log(Level.INFO, "Attempt to merge with head of cluster tree aborted");
                                break;
			}
			// *
			try {
				c1 = ClusterUtils.lookupIndexInTree(nextInstruction.getOperand1(), tree);
			} catch (UndefinedIndexException e) {
                             Logger.getLogger(VecInterpreter.class.getName()).log(Level.WARNING, "First operand of MERGE not found", e);
				c1 = e.getDefaultNode();

			}
			try {
				c2 = ClusterUtils.lookupIndexInTree(nextInstruction.getOperand2(), tree);
			} catch (UndefinedIndexException e) {
                                Logger.getLogger(VecInterpreter.class.getName()).log(Level.WARNING, "Second operand of MERGE not found", e);
				c2 = e.getDefaultNode();

			}
			


			// */
			ClusterUtils.merge(c2, c1, tree); // */
			// ClusterUtils.prettyPrintTree(tree);
			break;
		case SPLIT:
			try {
				// ClusterUtils.split(tree,
				// ClusterUtils.lookupIndexInTree(tree,nextInstruction.getOperand1()));
				ClusterNode toSplit = (ClusterNode) ClusterUtils.lookupIndexInTree(nextInstruction.getOperand1(), tree);
				ClusterNode parent = (ClusterNode) ClusterUtils.findParent(
						toSplit, tree);
				ClusterUtils.explode(toSplit, parent, tree);
			} catch (UndefinedIndexException e) {
                                Logger.getLogger(VecInterpreter.class.getName()).log(Level.WARNING, "Operand of SPLIT instruction not found", e);
				// ClusterUtils.split(tree, e.getDefaultNode());
			}
			break;
		case MOVE:
			/**/

			if (nextInstruction.getOperand1() == nextInstruction.getOperand2())
				break;
                        if (nextInstruction.getOperand1() == 0
					|| nextInstruction.getOperand2() == 0) {
				                        Logger.getLogger(VecInterpreter.class.getName()).log(Level.INFO, "Attempt to move node into head aborted");

			}
			try {
				c1 = ClusterUtils.lookupIndexInTree(nextInstruction.getOperand1(), tree);
			} catch (UndefinedIndexException e) {
                                Logger.getLogger(VecInterpreter.class.getName()).log(Level.WARNING, "First operand of MOVE not found", e);
				c1 = e.getDefaultNode();

			}
			try {
				c2 = ClusterUtils.lookupIndexInTree(nextInstruction.getOperand2(), tree);
			} catch (UndefinedIndexException e) {
				Logger.getLogger(VecInterpreter.class.getName()).log(Level.WARNING, "Second operand of MOVE not found", e);
				c2 = e.getDefaultNode();
			}
			
			if (!c2.encapsulates())
				break;
			boolean ok = true;
                        List<Integer> c1ids = ClusterUtils.getIDs(c1);
                        List<Integer> c2ids = ClusterUtils.getIDs(c2);
                        
                       

			for (int id : c2ids) {
				if (c1ids.contains(id)&& id != -1)
					ok = false;
			}
			for (int id : c1ids) {
				if (c2ids.contains(id) && id != -1)
					ok = false;
			}
			if (!ok)
				break;
			if (c2ids.contains(nextInstruction.getOperand1()))
				break;
			ClusterUtils.move(c1, (ClusterNode) ClusterUtils.findParent(c1,
					tree), (ClusterNode) c2, tree);

			// */
			break;
		case NOP:
		default:
			break;

		}

	}




}
